package com.cjf.aop.runtime.aspectj;

import com.cjf.aop.annotation.Intercept;
import com.cjf.aop.runtime.AOPManager;
import com.cjf.aop.runtime.logger.XLogger;
import com.cjf.aop.runtime.utils.Utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

/**
 * 自定义拦截切片
 * created by cjf
 * on: 2020/3/25
 */
@Aspect
public class InterceptAspectJ {

    /**
     * 带 {@link com.cjf.aop.annotation.Intercept} 注解的所有类
     */
    @Pointcut("within(@com.cjf.aop.annotation.Intercept *)")
    public void withinAnnotatedClass() {
    }

    //带有@Intercept注解的所有类，除去synthetic修饰的方法
    @Pointcut("execution(!synthetic * *(..)) && withinAnnotatedClass()")
    public void methodInsideAnnotatedType() {
    }

    //带有@Intercept注解的所有类，除去synthetic修饰的构造方法
    @Pointcut("execution(!synthetic *.new(..)) && withinAnnotatedClass()")
    public void constructorInsideAnnotatedType() {
    }

    //方法切入点，带有@Intercept注解的方法,或者带有@DIntercept注解的类并除去synthetic修饰的方法
    @Pointcut("execution(@com.cjf.aop.annotation.Intercept * *(..)) || methodInsideAnnotatedType()")
    public void method() {
    }

    //构造器切入点，带有@Intercept注解的方法,或者带有@DIntercept注解的类并除去synthetic修饰的方法
    @Pointcut("execution(@com.cjf.aop.annotation.Intercept *.new(..)) || constructorInsideAnnotatedType()")
    public void constructor() {
    }

    @Around("(method() || constructor()) && @annotation(intercept)")
    public Object aroundJoinPoint(ProceedingJoinPoint joinPoint, Intercept intercept) throws Throwable {
        if (AOPManager.getInstance().getInterceptor() == null) {
            return joinPoint.proceed(); //没有拦截器不执行切片拦截
        }
        //执行拦截操作
        boolean result = proceedIntercept(intercept.value(), joinPoint);
        XLogger.d(Utils.getMethodDescribeMsg(joinPoint) + " \u21E2 拦截结果:" + result + ", 切片" + (result ? "被拦截！" : "正常执行！") + " \u21E0");
        return result ? null : joinPoint.proceed();
    }

    /**
     * 执行拦截操作
     *
     * @param types     拦截的类型集合
     * @param joinPoint 切片
     * @return {@code true}: 拦截切片的执行 <br>{@code false}: 不拦截切片的执行
     */
    private boolean proceedIntercept(int[] types, ProceedingJoinPoint joinPoint) throws Throwable {
        for (int type : types) {
            if (AOPManager.getInstance().getInterceptor().intercept(type, joinPoint)) {//拦截执行
                return true;
            }
        }
        return false;
    }
}
